#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/slab.h>
#include<linux/timer.h>//timer_list
#include<linux/sched.h>//jiffies
#include<linux/list.h>//container_of
#include<linux/interrupt.h>


MODULE_AUTHOR("Tan xujia");
MODULE_LICENSE("Dual BSD/GPL");

DECLARE_WAIT_QUEUE_HEAD(wq);

struct tasklettest {
    struct tasklet_struct tsklt;;
    int count;
};

struct tasklettest *ttest;

void 
tasklet_fn(unsigned long data)
{
    printk("tasklet_fn\n");
    struct tasklettest *p =(struct tasklettest*)data;
    if (--(p->count)) {
        tasklet_hi_schedule(&p->tsklt);
        //tasklet_schedule(&p->tsklt);
    } else {
        //tasklet_kill(&ttest->tsklt);,在这里用这个会有问题
        wake_up_interruptible(&wq);//唤醒
        printk("wait up\n");
    }
}

static
int __init hello_init (void)
{
    printk("hello_init\n");
    ttest = (struct tasklettest *)kzalloc(sizeof(*ttest), GFP_KERNEL);
    ttest->count = 10;
    tasklet_init(&ttest->tsklt, tasklet_fn, (unsigned long)ttest);
    tasklet_hi_schedule(&ttest->tsklt);
    //tasklet_schedule(&ttest->tsklt);
    wait_event_interruptible(wq, !ttest->count);//等待条件满足以后，程序继续往下走
    printk("wait event\n");   
    tasklet_kill(&ttest->tsklt);
    return 0;
}

static
void __exit hello_exit (void)
{
    //tasklet_kill(&ttest->tsklt);
    kfree(ttest);
    printk("hello_exit\n");
}

module_init(hello_init);
module_exit(hello_exit);